<template>
  <div>
    <el-upload
      v-bind="$attrs"
      ref="uploadRef"
      v-model:file-list="newFileList"
      class="k-image-uploader"
      list-type="picture-card"
      :limit="1"
      :disabled="disabled"
      :on-preview="handlePreview"
      :on-exceed="handleExceed"
      :before-upload="handleBeforeUpload"
    >
      <slot name="default">
        <el-icon><Plus /></el-icon>
      </slot>
      <template v-if="tip?.length" #tip>
        <div class="upload-tip-text">
          <slot name="tip">{{ tip }}</slot>
        </div>
      </template>
    </el-upload>
    <!-- 预览图片 -->
    <el-dialog v-model="visible" unmount-on-close>
      <div class="k-image-uploader__content">
        <el-image fit :src="previewUrl" />
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, nextTick } from 'vue';
import type { IProps } from './types';
import { Plus } from '@element-plus/icons-vue';
import { genFileId } from 'element-plus';
// eslint-disable-next-line no-duplicate-imports
import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus';
import { fileToBase64 } from '@/utils/file';
import { uploadImage } from '@/api/upload';

defineOptions({ name: 'KImgUploader' });
const newFileList = ref<any[]>([]);
const visible = ref(false);
const previewUrl = ref('');
const imageUrl = ref<string | undefined>(undefined);
const uploadRef = ref<UploadInstance>();

const props = withDefaults(defineProps<IProps>(), {
  fileList: [],
  tip: '',
  disabled: false,
  onBeforeUpload: () => true
});
/** 在图片上传之前校验 */
const handleBeforeUpload: UploadProps['beforeUpload'] = async (rawFile) => {
  const isPass = props.onBeforeUpload?.(rawFile);
  if (isPass) {
    await handleUploadImg(rawFile);
  }
  return false;
};
const handleExceed: UploadProps['onExceed'] = async (files) => {
  uploadRef.value?.clearFiles();
  const file = files[0] as UploadRawFile;
  file.uid = genFileId();
  if (props?.onBeforeUpload?.(file)) {
    await handleUploadImg(file);
    nextTick(() => {
      const list = newFileList.value.pop();
      newFileList.value = [list];
    });
  }
};
/** 执行上传图片 */
const handleUploadImg = async (file: any) => {
  imageUrl.value = '';
  const baseStr = (await fileToBase64(file)) as string;
  const imgStr = baseStr.split('base64,')[1];
  const res = await uploadImage({
    base64_image: imgStr
  });
  if (!res.err) {
    const { url } = res.data || {};
    imageUrl.value = url;
    uploadRef.value?.handleStart(file);
  }
};
/** 预览图片 */
const handlePreview: UploadProps['onPreview'] = (file) => {
  previewUrl.value = file.url as string;
  visible.value = true;
};
/** 获取上传后的图片的URL */
const getImgUrl = () => {
  return newFileList.value?.length ? imageUrl.value : undefined;
};
/** 有默认图片时，显示默认图片 */
watch(
  () => props.fileList,
  (fileList) => {
    newFileList.value = fileList;
    if (fileList.length) imageUrl.value = fileList[0];
  },
  {
    immediate: true
  }
);
/** 暴露获取URL的方法 */
defineExpose({
  getImgUrl
});
</script>

<style lang="scss">
.k-image-uploader {
  display: flex;
  align-items: center;

  .el-upload--picture-card {
    --el-upload-picture-card-size: 100px;

  }

  .el-upload-list--picture-card {
    --el-upload-list-picture-card-size: 100px;
  }

  .upload-tip-text {
    display: inline-flex;
    align-items: center;
    height: 100px;
    padding-left: 5px;
    font-size: 14px;
    color: #bbb;
  }

  .el-upload-list {
    &.is-disabled {
      .el-upload--picture-card {
        color: var(--el-button-disabled-text-color);
        cursor: not-allowed;
        background-color: var(--el-button-disabled-bg-color);
        background-image: none;
        border-color: var(--el-button-disabled-border-color);
      }
    }
  }
}

.k-image-uploader__content {
  display: flex;
  justify-content: center;
}
</style>
